package com.yifeng.repo.base.utils.codec;

import com.google.common.base.Strings;
import com.yifeng.repo.base.utils.common.Snowflake;
import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.DefaultClaims;
import io.jsonwebtoken.security.Keys;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * jwt签名工具
 * @author maoyun
 * @version 1.0.0
 */
public class JwtHelper {

    private static final Logger LOGGER = LoggerFactory.getLogger(JwtHelper.class);

    /**
     * 过期时间 默认24小时
     */
    private static final long EXPIRE_DAY_MILLS = 24*3600*1000L;

    /**
     * 生成jwt token
     * @param claimMap 业务数据body
     * @param secret jwt 加签秘钥
     * @return
     */
    public static String jwtToken(Map<String, Object> claimMap, String secret){

        return jwtToken(null, claimMap, secret, EXPIRE_DAY_MILLS, SignatureAlgorithm.HS256);
    }

    /**
     * 生成jwt token
     * @param subject 主题
     * @param claimMap 业务数据body
     * @param secret 加签秘钥
     * @param expire 过期时间,单位: 毫秒，示例：设定一个小时过期时间：expire=3600000L
     * @param algorithm 签名算法
     * @see SignatureAlgorithm
     * @return
     */
    public static String jwtToken(String subject, Map<String, Object> claimMap, String secret, long expire, SignatureAlgorithm algorithm){
        Date date = new Date();
        date.setTime(System.currentTimeMillis() + expire);
        return Jwts.builder()
                .setClaims(new DefaultClaims(claimMap))
                .setSubject(subject)
                .setIssuedAt(new Date())
                .setExpiration(date)
                .signWith(Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8)), algorithm)
                .compact();
    }

    /**
     * 验证jwt token
     * @param token jwt token
     * @return 是否合法
     */
    public static boolean verifyToken(String token, String secret){
        JwtParserBuilder parserBuilder = Jwts.parserBuilder();
        JwtParser jwtParser = parserBuilder.build();
        if (jwtParser.isSigned(token)){
            parserBuilder.setSigningKey(secret.getBytes(StandardCharsets.UTF_8));
            try {
                parserBuilder.build().parse(token);
                return true;
            } catch (ExpiredJwtException e){
                LOGGER.warn("jwt token:{} expired", token);
            } catch (Exception e){
                LOGGER.error("verifyToken error", e);
            }
        }
        return false;
    }

    /**
     * 获取body部分内容
     * @param token jwt token
     * @param secret 加签secret
     * @return
     */
    public static Claims getClaims(String token, String secret){
        if (Strings.isNullOrEmpty(token)){
            return null;
        }
        try {
            Jwt<Header, Claims> parse = Jwts.parserBuilder()
                    .setSigningKey(secret.getBytes(StandardCharsets.UTF_8))
                    .build().parse(token);
            return parse.getBody();
        } catch (ExpiredJwtException e){
            LOGGER.warn("jwt token:{} expired", token);
        } catch (Exception e){
            LOGGER.error("getClaims error", e);
        }
        return null;
    }

    public static void main(String[] args) {
        String userName = "戴兵";
        String secret = "jOHmFl3GDowxKQeemA4s9ie57Aa3ZQkN";

        Map<String, Object> claims = new HashMap<>(3);
        claims.put("id", Snowflake.get().nextId());
        claims.put("code", "00115764");
        String token = JwtHelper.jwtToken(userName, claims, secret, 4* 60 * 60 * 1000, SignatureAlgorithm.HS256);
        System.out.println("token: " + token);

        Claims claims2 = JwtHelper.getClaims(token, secret);
        System.out.println("claims2: " + claims2);
    }

}
